package demo4;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Stack;

/**
 * for graph execrise 4-7
 */
public class GraphDemo2 {
    public Graph makeUpGraph(){
        return new Graph();
    }
    public Project makeUpProject(String name){
        return new Project(name);
    }
    @Setter
    @Getter
    public class Graph{
        ArrayList<Project> project = new ArrayList<Project>();
        HashMap<String, Project> hashMap = new HashMap<String, Project>();
        public void addEdge(String startName,String endName){
            hashMap.get(endName).addNeighbor(hashMap.get(startName));
        }
        public ArrayList<Project> buildGraph(String[] projects,String[][] dependence){

            Arrays.stream(projects).forEach(p->{
                Project project = new Project(p);
                this.project.add(project);
                hashMap.put(p,project);
            });

            for (int i = 0; i < dependence.length ; i++) {
                for (int j = 0; j < 1; j++) {
                    addEdge(dependence[i][j],dependence[i][j+1]);
                }
            }
            return project;

        }

    }
    public enum State{
        BLANK,PARTIAL,COMPLETE;
    };
    @NoArgsConstructor
    @Getter
    @Setter
    public class Project{
        private State state=State.BLANK;
        ArrayList<Project> children = new ArrayList<Project>();
        HashMap<String, Project> hashMap = new HashMap<String, Project>();
        private String name;
        public Project(String name){this.name=name;}

        public void addNeighbor(Project project){

            if(!project.hashMap.containsKey(this.getName())) {
                project.children.add(this);
                project.hashMap.put(this.getName(), project);
            }

        }
    }
    private boolean DFS(Project project, Stack<Project> stack){
         // adjust current project whether is
        if(project.state==State.PARTIAL){
            return false;
        }
        if(project.state==State.BLANK){
            ArrayList<Project> childs = project.getChildren();
            for (Project child : childs) {
                project.setState(State.PARTIAL);
                if(!DFS(child,stack)){
                    return false;
                }
            }
            stack.push(project);
            project.setState(State.COMPLETE);
        }
        return true;
    }
    public Stack<Project> orderProjects(ArrayList<Project> list){
        Stack<Project> stack = new Stack<>();

        for (Project project : list) {
            if(project.state==State.BLANK){
                if(!DFS(project,stack)){ // circular dependence
                    return null;
                }
            }
        }
        return stack;
    }

    public String stackToString(Stack<Project> projects){
        StringBuilder sb =new StringBuilder();
        while(!projects.isEmpty()){
            sb.append(projects.pop().getName()).append(",");
        }
        return sb.toString();
    }
    public Stack<Project> findBuildOrder(String[] projects,String[][] dependence){
        ArrayList<Project> projects1 = new Graph().buildGraph(projects,dependence);
        Stack<Project> order = orderProjects(projects1);
        return order;
    }


}
